#!/usr/bin/env python
# -*- coding: utf8 -*-
'''
Програма коллекция книг предназначена
для составления базы электронных книг в
формате djvu и pdf с удобным графическим
интерфейсом, возможностью поиска и др. 
возможностями

Автор: Шаптала М. <mshaptala@gmail.com>
'''
import os.path

import sys
import os
import re
import shelve
import ConfigParser
#import md5
import hashlib
import shutil
import gobject

# print __file__

try:
  import pygtk
  #tell pyGTK, if possible, that we want GTKv2
  pygtk.require("2.0")
except:
  print "You need to install pyGTK or GTKv2 or set your PYTHONPATH correctly"
  print "try: export PYTHONPATH=/usr/local/lib/python2.2/site-packages/"
  sys.exit(1)

import gtk
import gtk.glade

import re

# TODO: поиск файлов по расширению:
#
import fnmatch
#
# fileList = []
# ext = '*.djvu'
# 
# rootdir = '/home/max/books'
# for root, subFolders, files in os.walk(rootdir):
#     for file in files:
#         if fnmatch.fnmatch(file, ext):
#             fileList.append(os.path.join(root,file))
# print fileList

def debug_regex(regex, example):
    ''' Отладка рег. выражения. '''
    print 'Debug', regex, example
    last_good = ' '
    for i in range(1, len(regex)):
	try:
	    if re.compile(regex[:i]).match(example):
		last_good = regex[:i]
	except:
	    continue
    return last_good

def str_to_lower(s):
    ''' приводим к нижнему регистру для безрегистрового поиска '''
    return unicode(s).lower().encode('utf-8')
      
class search_app:
    """
    """
    def __init__(self, books):	
	self.books = books
	self.md5 = []	# md5sum файлов для идентификации
	#self.gladefile  = "glade/book_collection.glade"
        #self.gladefile = os.path.join(os.path.dirname(__file__),'glade/book_collection.glade')
	self.windowname = "window2"
	
	self.platform = sys.platform
	#self.xml = gtk.glade.XML(self.gladefile, self.windowname)
        self.xml = self.get_glade("book_collection.glade", self.windowname)
	#self.window = self.xml.get_widget(self.windowname)
	
	button = {}
	button['Search'] = self.xml.get_widget('button5')
	button['Close']  = self.xml.get_widget('button6')

	self.entry = {}
	self.entry['Search'] = self.xml.get_widget('entry9')
	

	dic = {
		"on_treeview1_row_activated" : self.row_activate,
		"on_search_clicked"          : self.search,
		"on_filter_changed"          : self.filter,
		"on_button6_clicked"	     : self.die,
		"on_entry9_key_press_event"  : self.key_press_entry9
	      }

	self.xml.signal_autoconnect (dic)

	self.treeview  = self.xml.get_widget('treeview1')

	# заполняем combobox
	column_txt = [u'Тип', u'Автор', u'Название']
	self.model_search = gtk.ListStore(gobject.TYPE_STRING)
	self.model_search.append([u'Везде'])
	for txt in column_txt:
	    self.model_search.append([txt])
	    pass

	self.combo = {}
	self.combo['Search'] = self.xml.get_widget("combobox1")
	self.combo['Search'].set_model(self.model_search)
	#cell = gtk.CellRendererText()
	#self.combo['Search'].pack_start(cell, True)
	#self.combo['Search'].add_attribute(cell,'text',0)
	self.combo['Search'].set_active(0)
	
	#columns
        #self.cCategory = 0
	#self.cAutor    = 1	
	#self.cName     = 2

        #self.sCategory = u'Тип'
	#self.sAutor    = u'Автор'
	#self.sName     = u'Название'

	for n, t in enumerate(column_txt):
	    print n, t
	    self.add_list_column(t, n)
	
	# Автор, Название
	self.list = gtk.ListStore(str, str, str)
	self.treeview.set_model(self.list)
	
	self.init_treeview(books)

	self.treeview.connect("button-press-event", self.popup_menu)

    def get_glade(self, fname, winname = None):
        glade_dir = 'glade'
        base_dir  = os.path.dirname(sys.argv[0])
	file_path = os.path.join(base_dir, glade_dir, fname)
	return gtk.glade.XML(file_path, root=winname)

    def clear_list(self):
	''' очищает список '''
	self.list.clear()
	self.md5 = []
	pass

    def search(self, widget):
	# поиск
	print "Search"
	find_txt = self.entry['Search'].get_text()
	lfind = str_to_lower(find_txt)
	print find_txt
	model = self.combo['Search'].get_model()
	active = self.combo['Search'].get_active()
	if active < 0:
	    fltr = None
	else:
	    fltr = model[active][0]
	print fltr

	if fltr == u'Везде':
	    '''Ищем везде'''
	    # очищаем список
	    self.clear_list()
	    import string
	    for item in self.books:
		category = self.books[item]['category']
		autor = self.books[item]['autor']
		name  = self.books[item]['name']
		# приводим к нижнему регистру для безрегистрового поиска
		lcat = str_to_lower(category) 
		laut = str_to_lower(autor)
		lnam = str_to_lower(name) 
		#file  = self.books[item]['file']

		if lcat.find(lfind) != -1 or\
		   laut.find(lfind) != -1 or\
		   lnam.find(lfind) != -1:
		       self.list.append([category, autor, name])
		       self.md5.append(item)

	elif fltr == u'Тип':
	    '''Ищим по полю Тип'''
	    # очищаем список
	    self.clear_list()
	    for item in self.books:
		category = self.books[item]['category']
		autor = self.books[item]['autor']
		name  = self.books[item]['name']
		# приводим к нижнему регистру для безрегистрового поиска
		lcat = str_to_lower(category) 

		if lcat.find(lfind) != -1:
		    self.list.append([category, autor, name])
		    self.md5.append(item)
	elif fltr == u'Автор':
	    ''' Поиск по полю Автор '''
	    # очищаем список
	    self.clear_list()
	    for item in self.books:
		category = self.books[item]['category']
		autor = self.books[item]['autor']
		name  = self.books[item]['name']
		# приводим к нижнему регистру для безрегистрового поиска
		laut = str_to_lower(autor) 

		if laut.find(lfind) != -1:
		    self.list.append([category, autor, name])
		    self.md5.append(item)
	elif fltr == u'Название':
	    # очищаем список
	    self.clear_list()
	    for item in self.books:
		category = self.books[item]['category']
		autor = self.books[item]['autor']
		name  = self.books[item]['name']
		# приводим к нижнему регистру для безрегистрового поиска
		lnam = str_to_lower(name) 

		if lnam.find(lfind) != -1:
		    self.list.append([category, autor, name])
		    self.md5.append(item)


	if find_txt == None:
	    print 'Нет'

    def key_press_entry9(self, widget, event):
	# обработка события нажатия кнопки
	from gtk.gdk import keyval_name
	#print "Key press...", keyval_name(event.keyval)

	if keyval_name(event.keyval) == "Return":
	    # нажата клавиша Enter
	    self.search(None)
	pass

    def filter(self, widget):
	print "filter"

    def edit_item(self, widget):
	print "edit"
	pass

    def info_item(self, widget):
	print "info"
	pass
    
    def add_to_archiv(self, widget):
	print "add to archive"
	pass

    def del_item(self, widget):
	print "delete item"
	pass

    def popup_menu(self, treeview, event):
        """Show popup menu"""
        if event.button == 3:
	    print 'press 3 button'
	    xml = gtk.glade.XML("glade/book_collection.glade", "menu1")
            menu = xml.get_widget("menu1")
            menu.popup(None, None, None, event.button, event.time)
	    dic = {
		    "on_open_activate"	     : self.row_activate,
		    "on_edit_activate"	     : self.edit_item,
		    "on_Info_activate"	     : self.info_item,
		    "on_archive_activate"    : self.add_to_archiv,
		    "on_delete_activate"     : self.del_item
		  }
	    xml.signal_autoconnect (dic)

    def add_list_column(self, title, columnId):
	"""This function adds a column to the list view.
	   First it create the gtk.TreeViewColumn and then set
	   some needed properties"""
        column = gtk.TreeViewColumn(title, gtk.CellRendererText(), text=columnId)
	column.set_resizable(True)
	column.set_sort_column_id(columnId)
	self.treeview.append_column(column)

    def init_treeview(self, books):
	for item in books:
	    category = books[item]['category']
	    autor = books[item]['autor']
	    name  = books[item]['name']
	    file  = books[item]['file']
	    
	    #print 'autor', autor
	    #print 'name', name
	    if autor or name:
		self.list.append([category, autor, name])
		self.md5.append(item)
		#print file

	self.window.show_all()

    def get_file_path(self, row=0):
	''' Возвращает полный путь к файлу '''
	books = self.books
	item = self.md5[row]
	return self.books[item]['file']
	#r = 0
	#for item in books:
	    #autor = books[item]['autor']
	    #name  = books[item]['name']
	    #file  = books[item]['file']
	    #if autor or name:
		#if row == r:
		    #return file
		#r +=1

    def row_activate(self, widget, path, column):
	print 'row_activated'
	row, = path
	print row
	file = self.get_file_path(row)
	if file and os.path.isfile(file):
	    if self.platform == 'linux2':
		os.system("gnome-open \"%s\"" % file.decode('utf-8'))
	    elif self.platform == 'win32':
		os.startfile(file.decode('utf-8'))

    def die(self, widget):
	self.window.destroy()

class Catalog:
    """
    """
    def __init__(self, books, xml):
	self.books = books
	self.md5 = []	# md5sum файлов для идентификации	
	self.windowname = "notebook2"

	self.platform = sys.platform	
        #self.xml = self.get_glade("book_collection_test.glade", self.windowname)
        self.xml = xml
	#self.window = self.xml.get_widget(self.windowname)

	button = {}
	button['Search'] = self.xml.get_widget('button7')	

	self.entry = {}
	self.entry['Search'] = self.xml.get_widget('entry11')

	dic = {
		"on_treeview1_row_activated" : self.row_activate,
		"on_search_clicked"          : self.search,
		"on_filter_changed"          : self.filter,		
		"on_entry9_key_press_event"  : self.key_press_entry9
	      }

	self.xml.signal_autoconnect (dic)

	self.treeview  = self.xml.get_widget('treeview2')

	# заполняем combobox
	column_txt = [u'№', u'Тип', u'Автор', u'Название']
	self.model_search = gtk.ListStore(gobject.TYPE_STRING)
	self.model_search.append([u'Везде'])
	for txt in column_txt:
	    self.model_search.append([txt])
	    pass

	self.combo = {}
	self.combo['Search'] = self.xml.get_widget("combobox2")
	self.combo['Search'].set_model(self.model_search)
	#cell = gtk.CellRendererText()
	#self.combo['Search'].pack_start(cell, True)
	#self.combo['Search'].add_attribute(cell,'text',0)
	self.combo['Search'].set_active(0)	

	for n, t in enumerate(column_txt):
	    print n, t
	    self.add_list_column(t, n, t)

	# №, Тип, Автор, Название
	self.list = gtk.ListStore(int, str, str, str)
	self.treeview.set_model(self.list)
        self.treeview.set_headers_visible(1)

	self.init_treeview(books)

	self.treeview.connect("button-press-event", self.popup_menu)

#        print "Catalog"
    def reinit(self, books, xml):
        self.__init__(books, xml)

    def get_glade(self, fname, winname = None):
        glade_dir = 'glade'
        base_dir  = os.path.dirname(sys.argv[0])
	file_path = os.path.join(base_dir, glade_dir, fname)
	return gtk.glade.XML(file_path, root=winname)

    def clear_list(self):
	''' очищает список '''
	self.list.clear()
	self.md5 = []
	pass

    def search(self, widget):
	# поиск
	print "Search"
	find_txt = self.entry['Search'].get_text()
	lfind = str_to_lower(find_txt)
	print find_txt
	model = self.combo['Search'].get_model()
	active = self.combo['Search'].get_active()
	if active < 0:
	    fltr = None
	else:
	    fltr = model[active][0]
	print fltr

	if fltr == u'Везде':
	    '''Ищем везде'''
	    # очищаем список
	    self.clear_list()
	    import string
            n = 1
	    for item in self.books:
		category = self.books[item]['category']
		autor = self.books[item]['autor']
		name  = self.books[item]['name']
		# приводим к нижнему регистру для безрегистрового поиска
		lcat = str_to_lower(category)
		laut = str_to_lower(autor)
		lnam = str_to_lower(name)
		#file  = self.books[item]['file']

		if lcat.find(lfind) != -1 or\
		   laut.find(lfind) != -1 or\
		   lnam.find(lfind) != -1:
		       self.list.append([n, category, autor, name])
		       self.md5.append(item)
                       n = n + 1

	elif fltr == u'Тип':
	    '''Ищим по полю Тип'''
	    # очищаем список
	    self.clear_list()
	    for item in self.books:
		category = self.books[item]['category']
		autor = self.books[item]['autor']
		name  = self.books[item]['name']
		# приводим к нижнему регистру для безрегистрового поиска
		lcat = str_to_lower(category)

		if lcat.find(lfind) != -1:
		    self.list.append([category, autor, name])
		    self.md5.append(item)
	elif fltr == u'Автор':
	    ''' Поиск по полю Автор '''
	    # очищаем список
	    self.clear_list()
	    for item in self.books:
		category = self.books[item]['category']
		autor = self.books[item]['autor']
		name  = self.books[item]['name']
		# приводим к нижнему регистру для безрегистрового поиска
		laut = str_to_lower(autor)

		if laut.find(lfind) != -1:
		    self.list.append([category, autor, name])
		    self.md5.append(item)
	elif fltr == u'Название':
	    # очищаем список
	    self.clear_list()
	    for item in self.books:
		category = self.books[item]['category']
		autor = self.books[item]['autor']
		name  = self.books[item]['name']
		# приводим к нижнему регистру для безрегистрового поиска
		lnam = str_to_lower(name)

		if lnam.find(lfind) != -1:
		    self.list.append([category, autor, name])
		    self.md5.append(item)

	if find_txt == None:
	    print 'Нет'

    def key_press_entry9(self, widget, event):
	# обработка события нажатия кнопки
	from gtk.gdk import keyval_name
	#print "Key press...", keyval_name(event.keyval)

	if keyval_name(event.keyval) == "Return":
	    # нажата клавиша Enter
	    self.search(None)
	pass

    def filter(self, widget):
	print "filter"

    def edit_item(self, widget):
	print "edit"
	pass

    def info_item(self, widget):
	print "info"
	pass

    def add_to_archiv(self, widget):
	print "add to archive"
	pass

    def del_item(self, widget):
	print "delete item"
	pass

    def popup_menu(self, treeview, event):
        """Show popup menu"""
        if event.button == 3:
	    print 'press 3 button'
	    xml = gtk.glade.XML("glade/book_collection.glade", "menu1")
            menu = xml.get_widget("menu1")
            menu.popup(None, None, None, event.button, event.time)
	    dic = {
		    "on_open_activate"	     : self.row_activate,
		    "on_edit_activate"	     : self.edit_item,
		    "on_Info_activate"	     : self.info_item,
		    "on_archive_activate"    : self.add_to_archiv,
		    "on_delete_activate"     : self.del_item
		  }
	    xml.signal_autoconnect (dic)

    def add_list_column(self, title, columnId, width=10):
	"""This function adds a column to the list view.
	   First it create the gtk.TreeViewColumn and then set
	   some needed properties"""
        #cell = gtk.CellRendererText()
        #cell.set_property('width', width)
        column = gtk.TreeViewColumn(title, gtk.CellRendererText(), text=columnId)
        #column = gtk.TreeViewColumn(title, text=columnId)
	column.set_resizable(True)
	column.set_sort_column_id(columnId)
        #column.pack_start(cell, False)
        #column.add_attribute(cell, 'text', 1)
        #column.set_property("width", width)
	self.treeview.append_column(column)

#        size_col = gtk.TreeViewColumn( _('Size') )
#        cell = gtk.CellRendererText()
#        cell.set_property('width', 90)
#        size_col.pack_start(cell, True)
#        size_col.add_attribute(cell, 'text', 1)
#        treeview.append_column(size_col)

    def init_treeview(self, books):
        n=1
	for item in books:
	    category = books[item]['category']
	    autor = books[item]['autor']
	    name  = books[item]['name']
	    file  = books[item]['file']

#	    print 'autor', autor
#	    print 'name', name
	    if autor or name:
		self.list.append([n, category, autor, name])
		self.md5.append(item)
                n = n+1
		#print file

	#self.window.show_all()

    def get_file_path(self, row=0):
	''' Возвращает полный путь к файлу '''
	books = self.books
	item = self.md5[row]
	return self.books[item]['file']
	#r = 0
	#for item in books:
	    #autor = books[item]['autor']
	    #name  = books[item]['name']
	    #file  = books[item]['file']
	    #if autor or name:
		#if row == r:
		    #return file
		#r +=1

    def row_activate(self, widget, path, column):
	print 'row_activated'
	row, = path
	print row
	file = self.get_file_path(row)
        print file
	if file and os.path.isfile(file):
	    if self.platform == 'linux2':
		os.system("gnome-open \"%s\"" % file.decode('utf-8'))
	    elif self.platform == 'win32':
		os.startfile(file.decode('utf-8'))

    def die(self, widget):
	self.window.destroy()

class AppGui:
    def __init__(self):
	"""
	In this init we are going to display the main serverinfo window
	"""
	self.set_default()
	self.read_config()
        #print 'database', self.database_path
        #print __file__
	self.books = self.read_database(self.database_path)

	#self.gladefile = os.path.join(os.path.dirname(__file__),'glade/book_collection.glade')
#	self.gladefile  = "glade/book_collection_test.glade"
        self.gladefile  = "book_collection_test.glade"
        self.glade_dir = "glade"
	self.windowname = "window1"
	#self.wTree = gtk.glade.XML(self.gladefile, self.windowname)
        #self.wTree = self.get_glade("book_collection.glade", self.windowname)
        self.wTree = self.get_glade(self.gladefile, self.windowname)
	self.win = self.wTree.get_widget(self.windowname)
	self.win.set_title('Book collection')

        #icon=os.path.join(os.path.dirname(__file__),'icons/devhelp-debian.xpm')
        base_dir = os.path.dirname(sys.argv[0])
        icon=os.path.join(base_dir, 'icons', 'devhelp-debian.xpm')
	self.win.set_icon_from_file(icon)
	
	self.filechoiser = self.wTree.get_widget('filechooserwidget1')
	self.file_extention = [ '.pdf', '.PDF', '.djvu', '.djv', '.DJV', '.DJVU' ]

        if self.init_dir:
	    self.filechoiser.set_current_folder(os.path.abspath(self.init_dir))
	self.set_file_filter(self.filechoiser)
	
	self.label['file'] = self.wTree.get_widget('label7')
	#self.label['file'].unmap()
	#self.label['file'].unrealize()
	#self.label['file'].hide_all()
	#self.label['f'] = self.wTree.get_widget('label4')
	#self.label['f'].unmap()
	#self.label['f'].unrealize()
	#self.label['f'].hide_all()
	
	self.field = [ 'autor', 'name', 'publishers', 'year', 'udk', 'bbk', 'isbn', 'source', 'city', 'pages' ]
	self.entry['autor']      = self.wTree.get_widget('entry1')
	self.entry['name']       = self.wTree.get_widget('entry3')
	self.entry['publishers'] = self.wTree.get_widget('entry2')
	self.entry['year']       = self.wTree.get_widget('entry4')
	self.entry['udk']        = self.wTree.get_widget('entry5')
	self.entry['bbk']        = self.wTree.get_widget('entry6')
	self.entry['isbn']       = self.wTree.get_widget('entry7')
	self.entry['source']     = self.wTree.get_widget('entry8')
	self.entry['city']       = self.wTree.get_widget('entry10')
	self.entry['pages']      = self.wTree.get_widget('entry_pages')
	
	self.combo['category'] = self.wTree.get_widget('comboboxentry1')

	self.combo['category'].set_active(0)

	self.text['annotation'] = self.wTree.get_widget('textview1')
        try: # проверка правописания
            import gtkspell
            self.spell = gtkspell.Spell(self.text['annotation'], lang="ru_RU")
        except:
            pass

	#we only have one callback to register, but you could register
	#any number, or use a special class that 
	#automatically registers all callbacks
	#button4 = self.wTree.get_widget("toolbutton4")
	#pixbuf = gtk.gdk.pixbuf_new_from_file('icons/devhelp-debian.xpm')
	#button4.set_icon('icons/devhelp-debian.xpm')
	
	dic = {
		"on_toolbutton4_clicked"   : self.search_widget,
		"on_file_browser_activate" : self.show_file_choiser,
		"on_toolbutton2_clicked"   : self.open,
		"on_Open_activate"	   : self.open,
                "find_books"               : self.find_books,
                "find_dublicate"           : self.find_dublicate,
		"on_About_activate"	   : self.about,
		"on_Ok_clicked"		   : self.ok,
		"on_Clear_clicked"	   : self.clear,
		"on_Save_activate"	   : self.save,
                "save_database_as"         : self.save_as,
                "on_Create_activate"       : self.new_database,
                "on_menu_database_add"     : self.add_database,
		"on_toolbutton3_clicked"   : self.save,
		"on_Quit1_activate"	   : self.destroy,
		"on_toolbutton5_clicked"   : self.destroy,
		"on_window1_destroy"	   : self.destroy,
		"on_filechooserwidget1_file_activated" : self.file_activated,
		"on_filechooserwidget1_selection_changed" : self.file_changed,
		"on_cover_drag_motion"     : self.cover_motion,
		"on_cover_drag_drop"       : self.cover_drop,
		"key_press_filechoise"     : self.key_press_filechoice
	      }
	
	cover = self.wTree.get_widget('cover')
	cover.drag_dest_set(0, [], 0)
	#cover.connect('drag_motion', self.motion_cb)
	#cover.connect('drag_drop', self.drop_cb)

	self.wTree.signal_autoconnect (dic)

        catalog = Catalog(self.books, self.wTree)

	self.statusbar_push(u'Готов')

    def get_glade(self, fname, winname = None):
        glade_dir = self.glade_dir
        base_dir  = os.path.dirname(sys.argv[0])
	file_path = os.path.join(base_dir, glade_dir, fname)
        if os.path.isfile(file_path):
            return gtk.glade.XML(file_path, root=winname)
        else:
            sys.exit(0)

    def delete_file(self, f):
	if os.path.isfile(f):
	    print "Удаление файла ", f
	    os.remove(f)
	elif os.path.isdir(f):
	    print "Удаление папки ", f
	    shutil.rmtree(f)

	pass

    def key_press_filechoice(self, widget, event):
	# обработка события нажатия кнопки в виджете
	# файлового менеджера
	#from gtk.gdk import SHIFT_MASK
	from gtk.gdk import keyval_name
	print "Key press...", keyval_name(event.keyval)

	if keyval_name(event.keyval) == "Delete":
	    # нажата клавиша Del
	    f = self.filechoiser.get_filename()
	    self.delete_file(f)
	pass

    def cover_motion(self, wid, context, x, y, time):
	context.drag_status(gtk.gdk.ACTION_COPY, time)
	#print 'motion'
	return True

    def cover_drop(self, wid, context, x, y, time):
	#l.set_text('\n'.join([str(t) for t in context.targets]))
	text = '\n'.join([str(t) for t in context.targets])
	print 'drop'
	print text
	print context.drag_get_selection()
	return True

    def set_default(self):
	# словарь данных о книгах
	self.books = {}

	self.label = {}
	self.entry = {}
        self.text  = {}
	self.combo = {}

	self.curr_file = '' # текущий файл книги

	self.platform = sys.platform

	if self.platform == 'linux2': # linux | unix
	    home_dir = os.path.expanduser('~') # домашний каталог
	    # стартовая директория 
	    self.init_dir = home_dir
	    # файл конфигурации
	    self.config_file = '.book_collection.cfg'
	elif self.platform == 'win32':
	    #http://snipplr.com/view/7354/get-home-directory-path--in-python-win-lin-other/
	    try:
		from win32com.shell import shellcon, shell
		home_dir = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0)
	    except ImportError: # quick semi-nasty fallback for non-windows/win32com case
		home_dir = os.path.expanduser("~")
	    # стартовая директория 
	    #self.init_dir = None
	    self.init_dir = home_dir
	    # файл конфигурации
	    self.config_file = 'book_collection.cfg'
	else:
	    home_dir = '.'

	self.config_dir  = home_dir
	self.config_path = os.path.join(self.config_dir, self.config_file)

        # база данных книг
	#self.database_file = 'book_database.dat' 
	#self.database_dir  = home_dir
	#self.database_path  = os.path.join(self.database_dir, self.database_file)
	self.database_path = None
	self.database_format = 'shelve'

    def set_file_filter(selt, dialog):
	filter = gtk.FileFilter()
	filter.set_name("All file")
	filter.add_pattern("*.*")
	dialog.add_filter(filter)

	filter = gtk.FileFilter()
	filter.set_name("PDF document")
	filter.add_mime_type("application/pdf")
	filter.add_pattern("*.pdf")
	filter.add_pattern("*.PDF")
	dialog.add_filter(filter)

	filter = gtk.FileFilter()
	filter.set_name("DjVu Image file")
	filter.add_mime_type("image/vnd.djvu")
	filter.add_pattern("*.djvu")
	filter.add_pattern("*.DJVU")
	filter.add_pattern("*.djv")
	filter.add_pattern("*.DJV")
	dialog.add_filter(filter)

    def read_config(self):
	''' Считываение конфигурационного файла '''
	init_dir  = self.init_dir
	conf_path = self.config_path
	data_path = self.database_path
	    
	if os.path.isfile(conf_path):
	    #f = open(conf_path, 'r')

	    #conf_re = re.compile(r'^\s*(?P<name>\w+)\s*:\s*(?P<conf>[\w\d./]+)\s*')
	    #for line in f.readlines():
		#m = conf_re.match(line)
		#conf = m.groupdict()
		#if conf['name'] == 'DatabaseFile':
		    #self.database_path = conf['conf']
		#elif conf['name'] == 'InitDir':
		    #self.init_dir = conf['conf']
	    #f.close()

	    cfg = ConfigParser.ConfigParser()
	    cfg.readfp(open(conf_path))
	    if cfg.has_section('Directory'):
		print 'Init dir:' 
		self.init_dir = cfg.get('Directory', 'start')
                print self.init_dir.decode("utf-8")
	    if cfg.has_section('Database'):
		print 'Database file:'
		self.database_path = cfg.get('Database', 'file')
		self.database_format = cfg.get('Database', 'format')
                print self.database_path.decode("utf-8")
	else:
	    #configure = { 'DatabaseFile' : data_path,
			  #'InitDir'	 : init_dir }
	    self.write_config(conf_path)

    def write_config(self, conf_file='.book_collection'):
        #f = open(conf_file, 'w')
	#name = ['DatabaseFile', 'InitDir']
	#for n in name:
	    #f.write("%s : %s\n" % (n, config[n]))
	#f.close()

	if not os.path.isfile(conf_file):            
	    f = open(conf_file, 'w')
	    f.write('[Directory]\n')
	    f.write('start = %s\n' % (self.init_dir))
	    f.write('[Database]\n')
	    f.write('format = %s\n' % (self.database_format))
	    f.write('file = %s\n' % (self.database_path))
	    f.close()
	else:
	    cfg = ConfigParser.ConfigParser()
	    try:
		cfg.readfp(open(conf_file))
	    except:
		sys.stderr('Not open config file '+conf_file)
	    if not cfg.has_section('Directory'):
		cfg.add_section('Directory')
	    directory = self.filechoiser.get_current_folder()
            print directory.decode('utf-8')
	    if directory and os.path.isdir(directory.decode('utf-8')):
                cfg.set('Directory', 'start', directory.decode('utf-8'))
	    else:
                cfg.set('Directory', 'start', '.')
	    if not cfg.has_section('Database'):
		cfg.add_section('Database')
	    cfg.set('Database', 'format', self.database_format)
	    cfg.set('Database', 'file', self.database_path.decode('utf-8'))

	    f = open(conf_file, 'w')
	    cfg.write(f)
	    f.close()

    def file_activated(self, widget):
	#print 'file activated', 
	fname = self.filechoiser.get_filename()
	if self.platform == 'linux2':
	    os.system("gnome-open \"%s\"" % fname.decode('utf-8'))
	elif self.platform == 'win32':
	    os.startfile(fname.decode('utf-8'))
    
    def file_changed(self, widget):
	label = self.label
	f = self.filechoiser.get_filename()
	if f:
	    file_path = f.decode('utf-8')
        else:
	    return 1

	if file_path and os.path.isfile(file_path):
	    name = os.path.basename(file_path)
	else:
	    self.curr_file = ''
	    return 1
	ext = os.path.splitext(name)[1]
	if ext in self.file_extention:
	    label['file'] = self.wTree.get_widget('label7')
	    label['file'].set_text(name)
	    self.curr_file = file_path
#	    self.md5sum = md5.new(open(file_path, 'rb').read()).hexdigest()
            self.md5sum = hashlib.md5(open(file_path, 'rb').read()).hexdigest()
	    #print self.md5sum
	    #if file_path in self.books.keys():
	    if self.md5sum in self.books.keys():
		self.stored(None)
	    else:
		self.clear(None)
	else:
	    self.clear(None)

	pass

    def changed_ctagory(self, widget):
	print "Changed comboboxentry"
    
    def statusbar_push(self, text):
        statusbar  = self.wTree.get_widget("statusbar")
        context_id = statusbar.get_context_id('context_descriptioni')
        message_id = statusbar.push(context_id, text)
        pass

    def add_new_category(self, text):
	'''
	Добавляем новую категорию
	'''
	print 'Новая категория:', text
	combo = self.combo

	combo['category'].prepend_text(text)
	# TODO: сохранить категории в файл бд

    def ok(self, widget):
	'''
	Действие при нажатие кнопки OK:

	добавляем описание для книги
	'''
	books = self.books
	label = self.label
	entry = self.entry
	combo = self.combo
	field = self.field
	text  = self.text['annotation']
	
	item = {}

	for f in field:
	    item[f] = entry[f].get_text()

	item['file'] = self.curr_file

        model = combo['category'].get_model()
	active = combo['category'].get_active()
	if active < 0:
	    text = combo['category'].get_active_text().decode('utf-8')
	    if text:
		self.add_new_category(text)
	    else:
		# FIXME: 
		#return None
		pass
	    return None
	item['category_active'] = active
	item['category'] = model[active][0].decode('utf-8')
	print item['category']

	buffer = text.get_buffer()
	start, end = buffer.get_bounds()
	item['annotation'] = buffer.get_text(start, end)

        if self.curr_file:
	    #books[self.curr_file] = item
	    books[self.md5sum] = item
	    #print books
	    self.statusbar_push(u'Добавлено описание %s' % self.curr_file)
	    pass
        #print item
	#print books

    def clear(self, widget):
	entry = self.entry
	field = self.field
	text  = self.text['annotation']
	combo = self.combo

	for f in field:
	    entry[f].set_text('')
	
	buffer = text.get_buffer()
	start, end = buffer.get_bounds()
	buffer.delete(start, end)
	
	combo['category'].set_active(0)
	
	self.statusbar_push(u'Готов')

    def get_file(self, dialogname):
	wTree = self.get_glade(self.gladefile, dialogname) #gtk.glade.XML (self.gladefile, dialogname)
	dialog = wTree.get_widget(dialogname)

	filter = gtk.FileFilter()
	filter.set_name("Book database")
	filter.add_pattern("*.dat")
	dialog.add_filter(filter)

	filter = gtk.FileFilter()
	filter.set_name("All file")
	filter.add_pattern("*.*")
	dialog.add_filter(filter)
	response = dialog.run()

        fname = ''
	if response == gtk.RESPONSE_OK:
	    fname = dialog.get_filename()
	    self.statusbar_push(u'Выбран файл %s' % fname)
	elif response == gtk.RESPONSE_CANCEL:
	    self.statusbar_push(u'Отмена')
	dialog.destroy()

	return fname

    def get_dir(self, dialogname):
	wTree = self.get_glade(self.gladefile, dialogname)
	dialog = wTree.get_widget(dialogname) 

	response = dialog.run()

        dname = ''
	if response == gtk.RESPONSE_OK:
	    dname = dialog.get_filename()
	    self.statusbar_push(u'Выбрана директория %s' % dname)
	elif response == gtk.RESPONSE_CANCEL:
	    self.statusbar_push(u'Отмена')
	dialog.destroy()
	return dname

    def new_database(self, widget):
        #TODO: create new database
        print "new databases"
        pass

    def destroy_widget(self, widget):
        widget.destroy()

    def dialog_ok(self, title, text):
        dialog = gtk.Window()
        dialog.set_size_request(450,100)
        dialog.set_position(gtk.WIN_POS_CENTER)
        dialog.set_title(title)
        md = gtk.MessageDialog(dialog, gtk.DIALOG_DESTROY_WITH_PARENT,
                               gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, text)
        md.run()
        md.destroy()
        pass

    def add_database(self, widget):
        print "add database"
        fname = self.get_file('fileopen')
#        self.dialog_ok("Добавлено","test")
	if os.path.isfile(fname.decode("utf-8")):
            print "update database books from file", fname
            items = len(self.books)
            print "old items in books database:", items
            new_books = self.read_database(fname)
            add_items = len(new_books)
            print "items in added database:", add_items
            self.books.update(new_books)
            new_items = len(self.books)
            print "new items in database books: ", new_items
            added = new_items - items
            print "Add items", added
            self.dialog_ok("Добавлено","Добавлено %d записей" % added)
        pass

    def save(self, widget):
	self.ok(None)
	print self.database_path
	if self.database_path is None:
	    self.database_path = self.get_file('filesave')
	    pass
	print self.database_path.decode('utf-8')
	self.save_database()
	self.statusbar_push(u'Сохранено %s' % self.database_path)

    def save_as(self, widget):
        self.ok(None)
	f = self.get_file('filesave')
        print "f = ", f.decode('utf-8')
        if not f is None:
            self.database_path = f
            print self.database_path
            self.save_database()
            self.statusbar_push(u'Сохранено как... %s' % self.database_path)

    def save_database(self):
	'''
	Сохранение бызы данных в формате xml
	'''
	field = self.field
	books = self.books

	keys = books.keys()
	#print keys

	for item in keys:
	    #print 'category :', books[item]['category'], books[item]['category_active']
	    #print 'file :', books[item]['file']
	    for f in field:
		#print f, ':', books[item][f]
		pass
	    #print 'annotation :', books[item]['annotation']
	   
	if self.database_path is None:
	    self.database_path = self.get_file('filesave')
	out = shelve.open(self.database_path)
	out['books'] = self.books
	out.close()

	#print self.books
	    
	pass

    def open(self, widget):
	fname = self.get_file('fileopen')
	if fname:
	    self.database_path = fname
	    self.books = self.read_database(fname)
	pass

    def read_database(self, data_file):
	'''
	Открытие и считывание базы данных из файла
	'''
        print "read data from file: ", data_file.decode("utf-8")
	if data_file and os.path.isfile(data_file.decode("utf-8")):
	    input = shelve.open(data_file)
	    data = input['books']
	    input.close()
#            print self.books
#            catalog.init_treeview(self.books)
#            catalog.reinit(self.books, self.wTree)

        else:
            "not read database"
            data = {}
	#print self.books
        return data
	pass
    
    def stored(self, widget):
	fname = self.curr_file
	books = self.books
	label = self.label
	entry = self.entry
	combo = self.combo
	md5sum = self.md5sum
	text  = self.text['annotation']
        
	field = self.field
	for f in field:
	    #entry[f].set_text(books[fname][f])
	    if books[md5sum].has_key(f):
		entry[f].set_text(books[md5sum][f])
	    else:
		entry[f].set_text('')
		print 'no key:', f
	
	#combo['category'].set_active(books[fname]['category_active'])
	if books[md5sum].has_key('category_active'):
	    combo['category'].set_active(books[md5sum]['category_active'])

	buffer = text.get_buffer()
	#buffer.set_text(books[fname]['annotation'])
	if books[md5sum].has_key('annotation'):
	    buffer.set_text(books[md5sum]['annotation'])
	
    def show_file_choiser(self, widget):
	''' отобразить / скрыть браузер файлов '''
	if not widget.get_active():
	    self.filechoiser.hide()
	else:
	    self.filechoiser.show()

    def find_books(self, widget):
        """
        Поиск файлов книг
        """
        # TODO: добавить индикатор поиска
        print "find books"
        fileList = []
        exts = ['*.djvu', '*.pdf', '*.djv']

        rootdir = self.get_dir("choose_dir").decode("utf-8")
        for root, subFolders, files in os.walk(rootdir):
            for file in files:
                for ext in exts:
                    if fnmatch.fnmatch(file, ext):
                        file_path = os.path.join(root,file.decode("utf-8"))
#                        md5sum = hashlib.md5.new(open(file_path, 'rb').read()).hexdigest()
                        md5sum = hashlib.md5(open(file_path, 'rb').read()).hexdigest()
                        if not self.books.has_key(md5sum):
                             fileList.append(file_path)
                        else:
                            if self.books[md5sum]['file'] != file_path:
                                print self.books[md5sum]['file'], " != ", file_path
                                self.books[md5sum]['file'] = file_path
        self.save_database()
#        for f in fileList:
#            print f

    def find_dublicate(self, widget):
        """
        Поиск дубликатов файлов на диске
        """
        # TODO: добавить индикатор поиска и вывода результатов
        print "find_dublicate"
        fileDic = {}
#        exts = ['*.djvu', '*.pdf', '*.djv', '*.DJVU', '*.DJV']
        exts = ['*.djvu', '*.pdf', '*.djv']

        rootdir = self.get_dir("choose_dir").decode("utf-8")
        for root, subFolders, files in os.walk(rootdir):
            for file in files:
                for ext in exts:
                    if fnmatch.fnmatch(file, ext):
                        file_path = os.path.join(root,file.decode("utf-8"))
#                        md5sum = md5.new(open(file_path, 'rb').read()).hexdigest()
                        md5sum = hashlib.md5(open(file_path, 'rb').read()).hexdigest()
                        if fileDic.has_key(md5sum):
                            fileDic[md5sum].append(file_path)
                        else:
                            fileDic[md5sum]=[file_path,]

        nd = {}
        for path_list in fileDic.values():
            l = len(path_list)
            if nd.has_key(l):
                nd[l] = nd[l] + 1
            else:
                nd[l] = 1
#            if len(path_list) > 1:
#                print len(path_list), ": ", path_list
        print nd
            
        pass

    def search_widget(self, widget):
	#search=search_app(self.books)
        #search=Catalog(self.books)

	#widget.show_all()
        pass

    def about(self, widget):
	aboutdialog = "aboutdialog1"
	awTree = gtk.glade.XML (self.gladefile, aboutdialog)
	dialog = awTree.get_widget("aboutdialog1")
	dialog.show()

    def destroy(self, widget):
	#conf_path = self.config_path
	#curr_dir = self.filechoiser.get_current_folder()
	#configure = { 'DatabaseFile' : self.database_path,
		      #'InitDir'	     : curr_dir }
	self.write_config(self.config_path)
	self.save(None)

	gtk.main_quit()

if __name__ == '__main__':
    app=AppGui()
    gtk.main()
#    raw_input("Press any key to exit...")
    #gtk.mainloop()
